package com.drakulo.games.ais.ui.state;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.newdawn.slick.Color;
import org.newdawn.slick.Font;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;

import com.drakulo.games.ais.AloneInSpace;
import com.drakulo.games.ais.core.Colony;
import com.drakulo.games.ais.core.GameData;
import com.drakulo.games.ais.core.GameEngine;
import com.drakulo.games.ais.core.Resource;
import com.drakulo.games.ais.core.ResourceHelper;
import com.drakulo.games.ais.core.Settings;
import com.drakulo.games.ais.core.delayed.HexagonMapAction;
import com.drakulo.games.ais.ui.FontHelper;
import com.drakulo.games.ais.ui.I18n;
import com.drakulo.games.ais.ui.ImageManager;
import com.drakulo.games.ais.ui.UIHelper;
import com.drakulo.games.ais.ui.component.ActionHandler;
import com.drakulo.games.ais.ui.component.ColonySelector;
import com.drakulo.games.ais.ui.component.HexagonMap;
import com.drakulo.games.ais.ui.component.ResourceDisplay;
import com.drakulo.games.ais.ui.component.TransferWindow;
import com.drakulo.games.ais.ui.component.button.ImageButton;
import com.drakulo.games.ais.ui.component.button.TextButton;

import de.matthiasmann.twl.EditField;
import de.matthiasmann.twl.model.SimpleChangableListModel;

public class PlanetState extends GameState {
	private static final int PADDING = 5;
	private static final int SIDEBAR_WIDTH = ColonySelector.WIDTH + PADDING * 2;

	/** The colony selectors */
	private List<ColonySelector> colonies;
	/** Selected colony */
	private Colony selectedColony;
	/** The planet exploration map */
	private HexagonMap map;
	/** The image background */
	private Image background;
	/** Exploration button */
	private ImageButton exploreButton;
	/** The access button : jump to the colony */
	private ImageButton viewButton;
	/** The colonize button */
	private ImageButton colonizeButton;
	/** The transfer button */
	private ImageButton transferButton;
	/** The selecting mode flag */
	private boolean selecting;
	/** Exploration selection */
	private boolean explorationSelection;
	/** Colonization selecting */
	private boolean colonizationSelection;
	/** The colony creation window */
	private boolean showNewColonyWindow;
	/** The button validating colony creation */
	private TextButton createColonyButton;
	/** The button canceling colony creation */
	private TextButton cancelColonyButton;
	/** The colony name field */
	private EditField colonyNameField;
	/** The resource display component */
	private ResourceDisplay resources;
	/** The transfer window */
	private TransferWindow transferWindow;
	/** The last colony count */
	private int lastColonyCount;

	public PlanetState(int id) {
		super(id);
	}

	@Override
	public void initState() throws SlickException {
		this.colonies = new ArrayList<ColonySelector>();
		for (Colony c : GameData.getColonies()) {
			this.colonies.add(new ColonySelector(c, getRootPane()));
		}
		this.map = new HexagonMap(4, 5, 64);

		int x = SIDEBAR_WIDTH + (Settings.WIDTH - SIDEBAR_WIDTH) / 2
				- this.map.getWidth() / 2;
		this.map.setOX(x);
		this.map.setOY(Settings.HEIGHT / 2 - this.map.getHeight() / 2);

		int i = 0;
		for (Colony c : GameData.getColonies()) {
			this.map.addColonyAt(c, i);
			i++;
		}

		this.background = ImageManager.getGfx("space_background");

		this.exploreButton = new ImageButton("exploration");
		this.exploreButton.setTitle(I18n.get("planet.explore_sector"));
		this.exploreButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				if (PlanetState.this.selectedColony == null) {
					// TODO play error sound
				} else {
					startZoneSelectionForExploration();
				}
			}
		});
		exploreButton.setHoverHandler(new ActionHandler() {

			@Override
			public void run() {
				// Exploration = 2500 Gas
				Map<Resource, BigDecimal> costMap = new HashMap<Resource, BigDecimal>();
				costMap.put(Resource.GAS, BigDecimal.valueOf(2500));
				resources.setMap(costMap);
				resources.show();
			}
		});
		add(this.exploreButton);

		this.viewButton = new ImageButton("home");
		this.viewButton.setTitle(I18n.get("planet.go_to_colony"));
		this.viewButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				if (PlanetState.this.selectedColony == null) {
					// TODO play error sound

				} else {
					GameData.setSelectedColony(PlanetState.this.selectedColony);
					GameData.getGame().enterState(AloneInSpace.SECTOR_STATE);
				}
			}
		});
		add(this.viewButton);

		this.colonizeButton = new ImageButton("top_right_expand");
		this.colonizeButton.setTitle(I18n.get("planet.colonize"));
		this.colonizeButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				if (PlanetState.this.selectedColony == null) {
					// TODO play error sound

				} else {
					// TODO Externalize
					Map<Resource, BigDecimal> costMap = new HashMap<Resource, BigDecimal>();
					for (Resource r : Resource.values()) {
						costMap.put(r, BigDecimal.valueOf(10000));
					}
					if (ResourceHelper.enoughResourcesFor(costMap)) {
						startZoneSelectionForColonization();
					} else {
						// TODO Play error sound
					}
				}
			}
		});
		this.colonizeButton.setHoverHandler(new ActionHandler() {

			@Override
			public void run() {
				// Colonization = 10.000 each
				Map<Resource, BigDecimal> costMap = new HashMap<Resource, BigDecimal>();
				for (Resource r : Resource.values()) {
					costMap.put(r, BigDecimal.valueOf(10000));
				}
				resources.setMap(costMap);
				resources.show();
			}
		});
		add(this.colonizeButton);


		transferButton = new ImageButton("transfer");
		transferButton.setTitle(I18n.get("planet.transfer"));
		transferButton.setActionHandler(new ActionHandler() {
			
			@Override
			public void run() {
				transferWindow.show();
			}
		});
		add(transferButton);
		
		this.showNewColonyWindow = false;
		this.createColonyButton = new TextButton(I18n.get("global.ok"));
		this.createColonyButton.setWidth(80);
		this.createColonyButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				final Colony c = new Colony();
				c.setName(PlanetState.this.colonyNameField.getText());
				PlanetState.this.colonyNameField.setText("");
				try {
					c.setMap(new TiledMap("data/testmap.tmx"));
				} catch (SlickException e) {
					// TODO Handle TiledMap loading in a manager
					e.printStackTrace();
				}
				c.setResource(Resource.CRISTAL, BigDecimal.valueOf(1000));
				c.setResource(Resource.ENERGY, BigDecimal.valueOf(1000));
				c.setResource(Resource.FOOD, BigDecimal.valueOf(1000));
				c.setResource(Resource.GAS, BigDecimal.valueOf(1000));
				final int selectedIndex = PlanetState.this.map
						.getSelectedZone();

				final HexagonMapAction a = new HexagonMapAction(2,
						PlanetState.this.map, PlanetState.this.map
								.getSelectedZone());
				a.setExploration(false);
				a.setCallback(new Runnable() {

					@Override
					public void run() {
						GameData.putInPool(c);
						PlanetState.this.map.addColonyAt(c, selectedIndex);

						// Create the new selector
						PlanetState.this.colonies.add(new ColonySelector(c,
								getRootPane()));
					}
				});

				GameData.addHexagonMapAction(a);
				stopZoneSelection();
				PlanetState.this.showNewColonyWindow = false;
			}
		});
		createColonyButton.hide();
		add(createColonyButton);

		this.cancelColonyButton = new TextButton(I18n.get("global.cancel"));
		this.cancelColonyButton.setWidth(80);
		this.cancelColonyButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				PlanetState.this.showNewColonyWindow = false;
				PlanetState.this.colonizationSelection = false;
			}
		});
		cancelColonyButton.hide();
		add(cancelColonyButton);

		this.colonyNameField = new EditField();
		this.colonyNameField.setVisible(false);
		this.getRootPane().add(this.colonyNameField);

		if (GameData.getSelectedColony() != null) {
			this.selectedColony = GameData.getSelectedColony();
		}

		// TODO Beaurk! Do this better inside of HexagonMap!
		x = map.getOX() + map.getWidth() + 10 + 1;
		int y = map.getOY() - 10;
		resources = new ResourceDisplay(getRootPane(), x, y);
		resources.hide();
		
		transferWindow = new TransferWindow(getRootPane());
		lastColonyCount = GameData.getColonies().size();
	}

	@Override
	public void renderState(Graphics g) throws SlickException {
		// The background (stars)
		g.drawImage(this.background, 0, 0);

		// Render UI
		UIHelper.drawDarkBox(g, 0, GameState.TOP_BAR_HEIGHT + 1, SIDEBAR_WIDTH,
				Settings.HEIGHT - 1 - GameState.TOP_BAR_HEIGHT);

		// Render the colony selectors
		int y = GameState.TOP_BAR_HEIGHT + PADDING * 2 + 10;
		for (ColonySelector cs : this.colonies) {
			if (cs == null) {
				UIHelper.drawBox(g, PADDING, y, ColonySelector.WIDTH,
						ColonySelector.HEIGHT);
				continue;
			}

			final boolean selected = cs.getColony().equals(this.selectedColony);
			cs.select(selected);
			cs.setOX(PADDING);
			cs.setOY(y);
			cs.render(g);
			y += ColonySelector.HEIGHT + PADDING;
		}

		// Action buttons background
		int width = PADDING * 5 + 4 * ImageButton.IB_DEFAULT_SIZE;
		int height = PADDING * 2 + ImageButton.IB_DEFAULT_SIZE;
		int x = SIDEBAR_WIDTH + (Settings.WIDTH - SIDEBAR_WIDTH) / 2 - width
				/ 2;
		y = Settings.HEIGHT / 2 - this.map.getHeight() / 2 - PADDING * 4
				- height;
		UIHelper.drawBox(g, x, y, width, height);

		// Buttons
		y += PADDING;
		this.viewButton.setPosition(x += PADDING, y);
		this.exploreButton.setPosition(x += ImageButton.IB_DEFAULT_SIZE
				+ PADDING, y);
		this.colonizeButton.setPosition(x += ImageButton.IB_DEFAULT_SIZE
				+ PADDING, y);
		transferButton.setPosition(x += ImageButton.IB_DEFAULT_SIZE
				+ PADDING, y);

		this.map.render(g);

		if (this.showNewColonyWindow) {
			// The colony creation is engaged. The player has to choose a name
			// for his new colony
			int w = 200;
			int h = 95;
			x = Settings.WIDTH / 2 - w / 2;
			y = Settings.HEIGHT / 2 - h / 2;
			UIHelper.drawWindow(g, x, y, w, h, 5);

			// The info label
			Font font = FontHelper.getFont(FontHelper.HEMI_HEAD, Color.white,
					16);
			font.drawString(x + 15, y + 15,
					FontHelper.firstToUpper(I18n.get("colony.create_label"))
							+ " :");

			this.cancelColonyButton.setPosition(x + 10, y + 65);
			this.createColonyButton.setPosition(x + w - 10
					- this.createColonyButton.getWidth(), y + 65);

			this.colonyNameField.setVisible(true);
			this.colonyNameField.setSize(w - 20, 20);
			this.colonyNameField.setPosition(x + 10, y + 35);
		} else {
			this.colonyNameField.setVisible(false);
		}

		resources.render(g);
		transferWindow.render(g);
	}

	@Override
	public void updateState(Input input, int time) throws SlickException {
		// Colony selectors update
		for (ColonySelector cs : this.colonies) {
			cs.update(input);
		}

		// Update hovered colony
		final int mx = input.getMouseX();
		if (mx < SIDEBAR_WIDTH) {
			// The mouse is in the sidebar, search for hover
			for (ColonySelector cs : this.colonies) {
				cs.update(input);
				if (cs.isHovered()) {
					if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)) {
						// Selected
						this.selectedColony = cs.getColony();
					}
				}
			}
		}

		int colonies = GameData.getColonies().size();
		List<HexagonMapAction> actions = GameData.getHexagonMapActions();
		for (HexagonMapAction a : actions) {
			if (!a.isExploration()) {
				colonies++;
			}
		}
		if (colonies == 6) {
			// Maximum of 6 colonies per planet (for now)
			this.colonizeButton.disable();
		}

		// The hexamap
		this.map.update(input);

		if (this.selecting && !showNewColonyWindow) {
			// Cancel selecting
			if (input.isKeyDown(Input.KEY_ESCAPE)
					|| input.isMousePressed(Input.MOUSE_RIGHT_BUTTON)) {
				stopZoneSelection();
			}
			if (this.map.getSelectedZone() != -1) {
				if (this.explorationSelection) {
					// A zone was selected
					// TODO Externalize values
					Map<Resource, BigDecimal> costMap = new HashMap<Resource, BigDecimal>();
					costMap.put(Resource.GAS, BigDecimal.valueOf(2500));
					if (!ResourceHelper.enoughResourcesFor(costMap)) {
						// Not enought resources
						// TODO Play error sound
					} else {
						GameData.getSelectedColony().updateResource(
								Resource.GAS, BigDecimal.valueOf(-2500));
						HexagonMapAction a = new HexagonMapAction(10, this.map,
								this.map.getSelectedZone());
						GameData.addHexagonMapAction(a);
						stopZoneSelection();
					}
				} else if (this.colonizationSelection) {
					this.showNewColonyWindow = true;
				}
			}
		}

		if (this.showNewColonyWindow) {
			createColonyButton.show();
			cancelColonyButton.show();
		} else {
			createColonyButton.hide();
			cancelColonyButton.hide();
		}

		resources.update(input);
		resources.hide();
		
		if(lastColonyCount != GameData.getColonies().size()){
			// New colonies were created, the lists must be updated
			lastColonyCount = GameData.getColonies().size();
			transferWindow.reloadList();
		}
		
		transferWindow.update(input);

		// Game logic update
		GameEngine.run(time);
	}

	private void startZoneSelectionForExploration() {
		this.selecting = true;
		this.explorationSelection = true;
		this.colonizationSelection = false;
		this.map.setSelectingMode(true, false);
	}

	private void startZoneSelectionForColonization() {
		this.selecting = true;
		this.colonizationSelection = true;
		this.explorationSelection = false;
		this.map.setSelectingMode(true, true);
	}

	private void stopZoneSelection() {
		this.selecting = false;
		this.explorationSelection = true;
		this.colonizationSelection = false;
		this.map.setSelectingMode(false, false);
	}
}
